How to get 'SkEncodedImageFormat' from 'SkImageGenerator'? - skia

The following is my implementation of reading a bitmap :
bool MySkia::readBitmap(std::string path, SkBitmap& dst) {
sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
if (data == nullptr) {
return false;
}
std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::MakeFromEncoded(std::move(data)));
gen && dst.tryAllocPixels(gen->getInfo()) &&
gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst.getPixels(), dst.rowBytes());
return true;
}
But I can't find any function to get 'SkEncodedImageFormat' from 'SkImageGenerator'?
It's possible?
By the way, I know other way to get 'SkEncodedImageFormat' :
std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(skData);
codec->getEncodedFormat();

Related

Get name of linux distribution running

Is there any way to get the linux distributionn name used to run a flutter app?
The only way I found is to parse the Platform.operatingSystemVersion string but I think if we can get it like so, Flutter team surely provide a proper way to do this?
By distribution name I mean Ubuntu, Fedora, Debian, etc.
First solution:
Found that device_info_plus_linux provide what I want.
To use it (without device_info_plus):
import 'package:device_info_plus_linux/device_info_plus_linux.dart';
import 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart' show LinuxDeviceInfo;
[...]
LinuxDeviceInfo deviceInfoLinux = await DeviceInfoLinux().linuxInfo();
print('Linux distribution: ${deviceInfoLinux.id}');
deviceInfoLinux.id will return a string containing the name of the distribution in lowercase characters (ex: 'debian', 'ubuntu', ...). If the package don't found any id it will return 'linux'.
Second solution:
In my case doing work async was not possible so I implemented my own solution:
String _getLinuxDistribution() {
String linuxDistribution;
try {
final List<String> osEtc = File('/etc/os-release').readAsLinesSync();
linuxDistribution =
osEtc.firstWhere((element) => element.indexOf("ID=") == 0);
if (linuxDistribution != null)
linuxDistribution = linuxDistribution.substring(3).toLowerCase();
else
throw Exception;
} catch (e) {
try {
final List<String> osUsr = File('/usr/lib/os-release').readAsLinesSync();
linuxDistribution =
osUsr.firstWhere((element) => element.indexOf("ID=") == 0);
if (linuxDistribution != null)
linuxDistribution = linuxDistribution.substring(3).toLowerCase();
else
throw Exception;
} catch (e) {
try {
final List<String> lsb = File('/etc/lsb-release').readAsLinesSync();
linuxDistribution =
lsb.firstWhere((element) => element.indexOf("DISTRIB_ID=") == 0);
if (linuxDistribution != null)
linuxDistribution = linuxDistribution.substring(11).toLowerCase();
else
throw Exception;
} catch (e) {
print(_red("Error getting Linux distribution name"));
linuxDistribution = 'linux';
}
}
}
return linuxDistribution;
}
note that the performance impact is negligable, I mesured it between 10ms and 30ms.

Problem using TVN_SELCHANGED seems to go in a continuous cycle

I have this event handler in a modelless popup dialog tree control:
void CAssignHistoryDlg::OnTvnSelchangedTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (!m_bBuildTreeMode)
{
if ((pNMTreeView->itemOld.hItem == nullptr && !m_bFirstSelChangeEvent) ||
pNMTreeView->itemOld.hItem != nullptr)
{
m_bFirstSelChangeEvent = true;
if (m_treeHistory.GetParentItem(pNMTreeView->itemNew.hItem) == nullptr)
{
// We must update the correct combo
// and associated string (in the SERVMEET_S structure)
if (m_pCombo != nullptr && m_pStrText != nullptr)
{
CString strExtractedName = ExtractName(pNMTreeView->itemNew.hItem);
m_pCombo->SetWindowText(strExtractedName);
*m_pStrText = strExtractedName;
}
GetParent()->PostMessage(UM_SM_EDITOR_SET_MODIFIED, (WPARAM)TRUE);
}
}
}
*pResult = 0;
}
What I don't understand is why once this event is triggered is that it goes in a continuous cycle.
Does anything jump out at you as wrong?
I don't know why the message seemed to be going in a continuous cycle. Maybe it was because I was inserting breakpoints or adding temporary popup message boxes to debug. Either way, I worked out the minor adjustment I needed:
void CAssignHistoryDlg::OnTvnSelchangedTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (!m_bBuildTreeMode)
{
if ((pNMTreeView->itemOld.hItem == nullptr && !m_bFirstSelChangeEvent) ||
pNMTreeView->itemOld.hItem != nullptr)
{
m_bFirstSelChangeEvent = true;
if (m_treeHistory.GetParentItem(pNMTreeView->itemNew.hItem) == nullptr)
{
// We must update the correct combo
// and associated string (in the SERVMEET_S structure)
if (m_pCombo != nullptr && m_pStrText != nullptr)
{
CString strExtractedName = ExtractName(pNMTreeView->itemNew.hItem);
m_pCombo->SetWindowText(strExtractedName);
// Bug fix - Only set as modified if the name is different
if(*m_pStrText != strExtractedName)
GetParent()->PostMessage(UM_SM_EDITOR_SET_MODIFIED, (WPARAM)TRUE);
*m_pStrText = strExtractedName;
}
}
}
}
*pResult = 0;
}
As you can see, I have changed how and where I post the UM_SM_EDITOR_SET_MODIFIED message. This causes my application to work correctly. Previously it was always setting it as modified (multiple times). So even if you had just saved the file, it then was marked as modified again. This problem no longer happens.

what's different between StrCmpW and wcscmp?

Actually i changed code to next.
struct myclass {
bool operator() (std::wstring p1, std::wstring p2) {
int result = 0;
//// If character is alphabet, sorting need converse.
wint_t a1 = p1.at(0);
wint_t b2 = p2.at(0);
int r1 = iswalpha(a1);
int r2 = iswalpha(b2);
**// return code of iswalpha.
// 257 is Upper Alphabet,
// 258 is Lower Alphabet**
if ((r1 == 257 && r1 == 258) ||
(r2 == 258 && r2 == 257)) {
result = p2.compare(p1);
}
else {
result = p1.compare(p2);
}
if (result != 0) {
if (result == -1) {
return true;
}
else {
return false;
}
}
return false;
}
} wStrCompare;
void main() {
std::vector<std::wstring> wlist;
wlist.emplace_back(L"가나");
wlist.emplace_back(L"123");
wlist.emplace_back(L"abc");
wlist.emplace_back(L"타파");
wlist.emplace_back(L"하하");
wlist.emplace_back(L"!##$");
wlist.emplace_back(L"一二三");
wlist.emplace_back(L"好好");
wlist.emplace_back(L"QWERID");
wlist.emplace_back(L"ⓐⓑ");
wlist.emplace_back(L"☆★");
wlist.emplace_back(L"とばす");
std::sort(wlist.begin(), wlist.end(), wStrCompare);
}
Test Result
L"!##$"
L"123"
L"abc"
L"QWERID"
L"ⓐⓑ"
L"☆★"
L"とばす"
L"一二三"
L"好好"
L"가나"
L"타파"
L"하하"
is this good?
Please give me a some opinion.
Thanks!!
I change my code, but i still want to know "is there difference between StrCmpW and wcscmp" Please talk to me. thanks!
Old question
I use qsort with std::wstring(for unicode string), and use StrCmpW.
Previously, I used StrCmpLogicalW() with CString, CStringArray.
(These are depend on windows)
But my code run in linux too, not only in windows.
(CString is ATL(afx), StrCmpLogicalW() is in Shlwapi.h)
So I use std::wstring and wcscmp, but result is different.
Is there a difference between StrCmpW() and wcscmp()?
The Following is my code.(exactly not mine lol)
int wCmpName(const void* p1, const void *p2)
{
std::wstring* wszName1 = ((std::wstring *)(p1));
std::wstring* wszName2 = ((std::wstring *)(p2));
int wret = StrCmpW(wszName1->c_str(), wszName2->c_str());
// int wret = wcscmp(wszName1->c_str(), wszName2->c_str());
// When i use wcscmp, different result comes out.
return wret;
}
void wSort(std::vector<std::wstring> &arr)
{
qsort(arr.data(), arr.size(), sizeof(std::wstring), wCmpName);
}
Thanks!
Test Code
void main() {
std::vector<std::wstring> wlist;
wlist.emplace_back(L"가나");
wlist.emplace_back(L"123");
wlist.emplace_back(L"abc");
wlist.emplace_back(L"타파");
wlist.emplace_back(L"하하");
wlist.emplace_back(L"!##$");
wlist.emplace_back(L"一二三");
wlist.emplace_back(L"好好");
wlist.emplace_back(L"QWERID");
wlist.emplace_back(L"ⓐⓑ");
wlist.emplace_back(L"☆★");
wlist.emplace_back(L"とばす");
wSort(wlist);
}
Test Result
wcscmp
L"!##$"
L"123"
L"QWERID"
L"abc"
L"ⓐⓑ"
L"☆★"
L"とばす"
L"一二三"
L"好好"
L"가나"
L"타파"
L"하하"
StrCmpW
L"!##$"
L"☆★"
L"123"
L"ⓐⓑ"
L"abc"
L"QWERID"
L"とばす"
L"가나"
L"一二三"
L"타파"
L"하하"
L"好好"
p.s : WHY limit reputation?! limited Images, limited URLs.
Only text takes so long time.

Accidently deleting entire linked list when trying to delete the head

I'm working on a checker's simulation game for my C++ class. My issue is with the linked list that holds the checkers. I can delete any checker perfectly with the exception of the head of the list. I've looked around here and other websites and I believe there's a memory leak somewhere. I'm fairly new to C++ so I'm not sure what to really do other than playing around with things (which will probably just create a bigger problem). I've never posted here before, so excuse me if the formatting is slightly off or too messy. I'll try to make it brief. First, here's a snippet of the node class for the linked list.
class CheckerpieceNode
{
private:
Checkerpiece *Node;
CheckerpieceNode *Next;
public:
CheckerpieceNode(); // sets Node and Next to NULL in .cpp file
void setNode(Checkerpiece *node);
void setNext(CheckerpieceNode *next);
Checkerpiece* getNode();
CheckerpieceNode* getNext();
};
And the functions are set up pretty much as you would expect in a Checkerpiece.cpp class.
Here's how the code is used. Its called by a Checkerboard object in my main class.
theCheckerboard.removeChecker(theCheckerboard.findChecker(selector->getCurrentX() + 0, selector->getCurrentY() - VERTICAL_SHIFT, listHead), listHead);
The VERTICAL_SHIFT simply has to do with the way my checkerboard graphic is on the console. Since it works perfectly for all other nodes (excluding the head) I've ruled it out as a source of error. Selector is a checkerpiece object but its not part of the list.
Here's the actual findChecker and removeChecker code from Checkerboard class.
Checkerpiece* findChecker(int x, int y, CheckerpieceNode* list_head)
{
if(list_head== NULL) return NULL; // do nothing
else
{
CheckerpieceNode* node = new CheckerpieceNode;
node = list_head;
while(node != NULL && node->getNode() != NULL)
{
if()// comparison check here, but removed for space
{
return node->getNode();
delete node;
node = NULL;
}
else // traversing
node = node->getNext();
}
return NULL;
}
}
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head)
{
if(list_head== NULL) // throw exception
else
{
CheckerpieceNode *temp = NULL, *previous = NULL;
Checkerpiece* c_checker= new Checkerpiece;
temp = list_head;
while(temp != NULL && temp->getNode() != NULL)
{
c_checker= temp->getNode();
if(d_checker!= c_checker)
{
previous = temp;
temp = temp->getNext();
}
else
{
if(temp != list_head)
{
previous->setNext(temp->getNext());
delete temp;
temp = NULL;
}
else if(temp == list_head) // this is where head should get deleted
{
temp = list_head;
list_head= list_head->getNext();
delete temp;
temp = NULL;
}
return;
}
}
}
}
Oh my, you're complicating it. Lots of redundant checks, assignments and unnecessary variables (like c_checker which leaks memory too).
// Write down the various scenarios you can expect first:
// (a) null inputs
// (b) can't find d_checker
// (c) d_checker is in head
// (d) d_checker is elsewhere in the list
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head) {
// first sanitize your inputs
if (d_checker == nullptr || list_head == nullptr) // use nullptr instead of NULL. its a keyword literal of type nullptr_t
throw exception;
// You understand that there is a special case for deleting head. Good.
// Just take care of it once and for all so that you don't check every time in the loop.
CheckerpieceNode *curr = list_head;
// take care of deleting head before traversal
if (d_checker == curr->getNode()) {
list_head = list_head->next; // update list head
delete curr; // delete previous head
return; // we're done
}
CheckerpieceNode *prev = curr;
curr = curr->next;
// traverse through the list - keep track of previous
while (curr != nullptr) {
if (d_checker == curr->getNode()) {
prev->next = curr->next;
delete curr;
break; // we're done!
}
prev = curr;
curr = curr->next;
}
}
I hope that helps. Take the time to break down the problem into smaller pieces, figure out the scenarios possible, how you'll handle them and only then start writing code.
Based on this edit by the question author, the solution he used was to:
I modified the code to show the address passing in the checker delete
function.
void delete_checker(Checker* d_checker, CheckerNode* &list_head) // pass by address
{
if(list_head== NULL) // throw exception
else
{
CheckerNode*temp = NULL, *previous = NULL;
Checker* c_checker= new Checker;
temp = list_head;
while(temp != NULL && temp->node!= NULL)
{
c_checker= temp->node;
if(d_checker!= c_checker)
{
previous = temp;
temp = temp->next;
}
else
{
if(temp != list_head)
{
previous->next = temp->next;
delete temp;
temp = NULL;
}
else if(temp == list_head) // this is where head should get deleted
{
temp = list_head;
list_head= list_head->next;
delete temp;
temp = NULL;
}
delete c_checker;
c_checker = nullptr;
return;
}
}
}
}
removeChecker cannot modify the value of list_head as it is past by value. The method signature should be:
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode** list_head)
// You will need to call this function with &list_head
or
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* &list_head)
// Calling code does not need to change

Comparing pointers fails mystically in VC++

I have a tree structure and I want to find all nodes matching a given criteria. Each time I call the find function, it returns next matching node. Children are searched by recursive function call.
For some reason a key comparison of pointers fails for this implementation. Please see the code below, I have pointed out the failing comparison.
HtmlTag* HtmlContent::FindTag(string tagName, string tagParameterContent)
{
if (tagName.empty() && tagParameterContent.empty())
return NULL;
if (this->startTag == NULL)
return NULL;
this->findContinue = this->FindChildren(this->startTag, &tagName, &tagParameterContent);
return this->findContinue;
}
HtmlTag* HtmlContent::FindChildren(HtmlTag* firstTag, string* tagName, string* tagParameterContent)
{
HtmlTag* currentTag = firstTag;
HtmlTag* childrenFound = NULL;
while (currentTag != NULL)
{
if (!tagName->empty() && *tagName == currentTag->tagName)
{
if (tagParameterContent->empty() || currentTag->tagParameters.find(*tagParameterContent, 0) != -1)
{
if (this->findContinue == NULL)
break; // break now when found
else if (this->findContinue == currentTag) // TODO why this fails?
this->findContinue == NULL; // break on next find
}
}
if (currentTag->pFirstChild != NULL)
{
childrenFound = this->FindChildren(currentTag->pFirstChild, tagName, tagParameterContent);
if (childrenFound != NULL)
{
currentTag = childrenFound;
break;
}
}
currentTag = currentTag->pNextSibling;
}
return currentTag;
}
VC++ compiler accepts this code but for some reason I can't put a breakpoint on this comparison. I guess this is optimized out, but why? Why this comparison fails?
I think that you shoud replace == with = in assignment after comparison. Compiler optimalized this whole section because it doesnt do anything useful.

Resources